<template>
  <div id="app">
    <div
        class="panel"
        ref="panel"
        @dragover.prevent
        @drop="drop"
        @paste="handlePaste"
    >
      <dragger
          v-for="(item,i) in list"
          ref="widget"
          :key="item.id"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :z="item.z"
          class-name="my-class"
          class-name-active="my-active-class"
          class-name-dragging="my-dragging-class"
          @dragstop="dragging"
          @resizestop="resizing"
          :active="item.focused"
          :drag-cancel="'.drag-cancel'"
          @activated="onFocus(item)"
          @contextmenu.native.prevent="onContextMenuOpen($event,item)"
      >
        <component
            ref="component"
            class="inner-widget"
            :is="item.component"
            :value="item.value"
            :title="item.title"
            @dblEvent="dblEvent"
            @changeValue="changeValue"
            @changeTitle="changeTitle"
            @inputFocus="inputFocus(item)"
            @drop.native.stop="drop($event, i)"
        />
      </dragger>
    </div>
    <widget-list
        :widgetList="widgetList"
        @onWidgetMouseDown="onWidgetMouseDown"
        @upload="upload"
        ref="wh"
    />
    <context-menu ref="contextMenu">
      <li>
        <a href="#" @click.prevent="onLayerBottom">置底</a>
      </li>
      <li>
        <a href="#" @click.prevent="onLayerRemove">删除</a>
      </li>
    </context-menu>
    <el-dialog  width="80%" center :title="compTitle" :visible.sync="dialogTableVisible">
      <mavon-editor @change="changeMakedown" v-model="compValue"  :toolbars="markdownOption" ref=md  ></mavon-editor>
    </el-dialog>
<!--    <div class="roomId">房间号:{{this.uid}}</div>-->
    <div class="roomId">房间号:{{this.uid}}</div>
    <el-button v-show="this.uid === this.user.id" class="share" @click="share">{{this.roomState === 1 ? "取消协作":"协作"}}</el-button>
  </div>
</template>

<script>
//组件列表
import BoxComp from '@/components/boxComp'
import WidgetList from '@/components/widget-list'
import TextComp from '@/components/textComp'
import PicComp from '@/components/picComp'
import VideoComp from '@/components/videoComp'
import BarChartComp from '@/components/barChartComp'
import BoxMapComp from '@/components/boxMapComp'
import PageMapComp from '@/components/pageMapComp'
import MakedownComp from '@/components/makedownComp'
import AvatarComp from '@/components/avatarComp'
import ContextMenu from 'vue-context'
//静态配置
import * as CONFIG from '@/constant/config'
import { cloneDeep } from 'lodash'
let widgetX = 0;
let widgetY = 0;
let currentWidget = null;
let form = {};
let id = 0;

import socket from '@/socket/index'

export default {
  name: 'App',
  components: {
    ContextMenu,WidgetList,TextComp,PicComp,VideoComp,BarChartComp,BoxComp,PageMapComp,BoxMapComp,MakedownComp,AvatarComp
  },
  data(){
    return {
      connected:false,
      markdownOption: {
        bold: true, // 粗体
        italic: true, // 斜体
        header: true, // 标题
        underline: true, // 下划线
        strikethrough: true, // 中划线
        mark: true, // 标记
        superscript: true, // 上角标
        subscript: true, // 下角标
        quote: true, // 引用
        ol: true, // 有序列表
        ul: true, // 无序列表
        link: true, // 链接
        imagelink: true, // 图片链接
        code: true, // code
        table: true, // 表格
        fullscreen: true, // 全屏编辑
        readmodel: true, // 沉浸式阅读
        undo: true, // 上一步
        redo: true, // 下一步
        trash: true, // 清空
        navigation: true, // 导航目录
        alignleft: true, // 左对齐
        aligncenter: true, // 居中
        alignright: true, // 右对齐
        preview: true, // 预览
      },
      list:[],
      pages:[],
      html:"",
      widgetList:CONFIG.WIDGET_LIST,
      user: null,
      dialogTableVisible:false,
      compValue: "",
      compTitle:"",
      roomState: 0,
      blob: {}
    }
  },
  computed: {
    current(){
      return this.list.find(item=>item.focused)
    },
    uid(){
      return this.$route.params.uid
    },
    page(){
      return this.$route.params.page
    },
  },
  mounted() {

    document.addEventListener('keyup', this.onKeyUp);
    window.onbeforeunload = () =>
    {
      this.sendUserLeave()
      this.save()
    }
  },
  beforeDestroy () {
    document.removeEventListener('keyup', this.onKeyUp);
  },
  created(){

    this.user=localStorage.getItem('user')? JSON.parse(localStorage.getItem('user')):null,

    this.request.get("/room/"+this.uid).then(res=>{
      if(res.code == 200){
        if(res.data.state === 1){
          this.roomState = 1
          socket.connect();
          socket.emit('joinRoom',this.user.nickname,this.uid)
        }else{
          this.roomState = 0
        }
      }else{
        this.$message.error("保存失败")
      }
    })
    this.load()
    socket.on('user_enter', nickname=> {
        this.$message.success(nickname + "加入协作!!!")
    })
    socket.on('user_leave', nickname => {
      this.$message.warning(nickname + "退出协作!!!")
    })
    socket.on('user_edit', (list,page) => {
      if(page ==this.page){
        this.list = list
      }
    })
    socket.on('room_close', ()=> {
      alert("房间已关闭")
      this.$router.push( '/admin/'+this.user.id+'/'+1)
    })
  },
  watch: {
    $route(val,oldval) {
      if (this.$route.fullPath) {
        this.save(oldval.params.page)
        this.list=[]
        this.pages=[]
        this.load()
      }
    },
    current(val,oldval){
      if(val){
        this.compValue=val.value
        this.compTitle=val.title
      }
    },
  },
  methods: {
    handlePaste(event){
      //粘贴上传图片
      let txt = event.clipboardData.getData('Text')
      if(typeof(txt) == 'string' && txt !== '') {
        //检测到是文字，过滤
        return ;
      }
      let file = null
      const items = (event.clipboardData || window.clipboardData).items
      if(items.length) {
        for (let i = 0; i < items.length; i++) {
          if (items[i].type.indexOf('image') !== -1) {
            file = items[i].getAsFile()
            this.handleChange(file)
            if (!this.canUpload) {
              this.canUpload = !this.canUpload;
            }
            break
          }
        }
      }
    },
    // 图片上传
    handleChange(file) {
      let formData = new FormData()
      formData.append('file', file.raw || file)
      this.request.post("/file/upload",formData).then(res=>{
        if(res.code == 200){
          this.upload(res)
        }else{
          this.$message.error("保存失败")
        }
      })
    },
    onKeyUp (e) {
      e.preventDefault();
      switch (e.key) {
        case 'Shift':
          this.multiable = false;
          break;
        default:
          break;
      }
      // ctrl + z 撤回
      if (e.ctrlKey && e.key === 'z') {
        this.pasteOption();
      }
    },
    pasteOption() {
      alert("?")

    },
    sendUserLeave() {
      socket.emit('leaveRoom',this.user.nickname,this.uid)
    },
    share() {
      const roomInfo = {}
      if(this.roomState === 0){
        this.roomState=1
      }else{
        alert("踢掉所有人")
        socket.emit('killRoom',this.user.id)
        this.roomState=0
      }
      const user = localStorage.getItem('user')? JSON.parse(localStorage.getItem('user')):null
      if(user){
        roomInfo.id=user.id
        roomInfo.state=this.roomState
        this.request.post("/room",roomInfo).then(res=>{
          if(res.code == 200){
          }else{
            this.$message.error("保存失败")
          }
        })
      }
    },
    changeMakedown(value,render){
      this.changeValue(value)
    },
    dblEvent(){
      this.dialogTableVisible=true

    },
    save(pid){
        for(let i=0; i<this.list.length; i++){
          form.id =this.list[i].id
          form.uid=this.uid
          form.component=this.list[i].component
          if(pid){
            form.page= pid
          }else{
            form.page= this.page
          }
          form.x=this.list[i].x
          form.y=this.list[i].y
          form.w=this.list[i].w
          form.h=this.list[i].h
          form.z=this.list[i].z
          form.value=this.list[i].value
          form.title=this.list[i].title
          this.request.post("/comp",form).then(res=>{
            if(res.code == 200){
            }else{
              this.$message.error("保存失败")
            }
          })
        }
    },
    resizing (x,y,width,height) {
      const currentItem = this.list.find(item => item.focused);
      if(width){
        currentItem.w = width;
      }
      if(height){
        currentItem.h = height;
      }
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    dragging (x,y) {
      const currentItem = this.list.find(item => item.focused);
      if(x){
        currentItem.x = x;
      }
      if(y){
        currentItem.y = y;
      }
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    getRandomString(len){
      let _charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789',
          min = 0,
          max = _charStr.length-1,
          _str = '';                    //定义随机字符串 变量
      //判断是否指定长度，否则默认长度为15
      len = len || 15;
      //循环生成字符串
      for(var i = 0, index; i < len; i++){
        index = (function(randomIndexFunc, i){
          return randomIndexFunc(min, max, i, randomIndexFunc);
        })(function(min, max, i, _self){
          let indexTemp = Math.floor(Math.random()*(max-min+1)+min),
              numStart = _charStr.length - 10;
          if(i==0&&indexTemp >=numStart){
            indexTemp = _self(min, max, i, _self);
          }
          return indexTemp ;
        }, i);
        _str += _charStr[index];
      }
      return _str;
    },
    matchType(fileName) {
      var suffix = '';
      var result = '';
      try {
        var flieArr = fileName.split('.');
        suffix = flieArr[flieArr.length - 1];
      } catch (err) {
        suffix = '';
      }
      if (!suffix) {
        result = false;
        return result;
      }
      // 图片格式
      var imglist = ['png', 'jpg', 'jpeg', 'bmp', 'gif'];
      // 进行图片匹配
      result = imglist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'PicComp';
        return result;
      }
      ;
      // 匹配txt
      var txtlist = ['txt'];
      result = txtlist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'txt';
        return result;
      }
      ;
      // 匹配 excel
      var excelist = ['xls', 'xlsx'];
      result = excelist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'excel';
        return result;
      }
      ;
      // 匹配 word
      var wordlist = ['doc', 'docx'];
      result = wordlist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'word';
        return result;
      }
      ;
      // 匹配 pdf
      var pdflist = ['pdf'];
      result = pdflist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'pdf';
        return result;
      }
      ;


      // 匹配 ppt
      var pptlist = ['ppt'];
      result = pptlist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'ppt';
        return result;
      }
      ;
      // 匹配 视频
      var videolist = ['mp4', 'm2v', 'mkv'];
      result = videolist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'VideoComp';
        return result;
      }
      ;
      // 匹配 音频
      var radiolist = ['mp3', 'wav', 'wmv'];
      result = radiolist.some(function (item) {
        return item == suffix;
      });
      if (result) {
        result = 'radio';
        return result;
      }
      // 其他 文件类型
      result = 'other';
      return result;
    },
    upload(res){
      const newItem = {
        id: !this.list.length ? 0 : Math.max(...this.list.map(item => item.id)) +1,
        x: 1296,
        y: 43,
        z: !this.list.length ? 0 : Math.max(...this.list.map(item => item.z)) +1,
        w: 300,
        h: 200,
        value: res.data,
        component: this.matchType(res.data),
      }
      this.list.push(newItem);
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    changeValue(newValue){
      const currentItem = this.list.find(item => item.focused);
      currentItem.value = newValue
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    changeTitle(newValue){
      const currentItem = this.list.find(item => item.focused);
      currentItem.title = newValue
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    inputFocus(item){
      this.onFocus(item)
    },
    load(){

      this.list=[]
        this.request("/comp/current/"+this.uid+"/"+this.page).then(res=>{
        if(res.code == 200){
          for(let i = 0; i < res.data.length; i++){
            const newItem = {
              id:res.data[i].id,
              x: res.data[i].x,
              y: res.data[i].y,
              z: res.data[i].z,
              w: res.data[i].w,
              h: res.data[i].h,
              title:res.data[i].title,
              uid:res.data[i].uid,
              page:res.data[i].page,
              component: res.data[i].component,
              value:res.data[i].value,
            }
            this.list.push(newItem);
          }
        }else{
          this.$message.error("导入失败,不能保存组件信息,请刷新页面重试")
        }
      })
      this.request("/comp/uid/"+this.uid).then(res=>{
        if(res.code == 200){
          for(let i = 0; i <res.data;i++){
          }
          this.pages.push(res.data)
        }else{
          this.$message.error("失败")
        }
      })
    },
    findTopLayerZ (currentItem) {
      const maxZ = Math.max(...this.list.map(item => item.z)) || 0;
      if (currentItem.z === maxZ) {
        return;
      }
      return maxZ;
    },
    findBottomLayerZ (currentItem) {
      const minZ = Math.min(...this.list.map(item => item.z)) || 0;
      if (currentItem.z === minZ) {
        alert('已经是最底层了');
        return false;
      }
      return minZ;
    },
    onLayerRemove () {
      const currentItem = this.list.find(item => item.focused);
      this.request.delete("/comp/"+currentItem.id).then(res=>{
        if(res.code == 200){
        }else{
        }
      })
      this.list = this.list.filter(item => !item.focused);
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    onLayerBottom () {
      const currentItem = this.list.find(item => item.focused);
      const minZ = this.findBottomLayerZ(currentItem);
      if (minZ === false) {
        return;
      }
      if (minZ - 1 < 0) {
        this.list = this.list.map(item => {
          item.z -= minZ - 1;
          return item;
        });
        currentItem.z = 0;
      } else {
        currentItem.z = minZ - 1;
      }
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    onFocus(current){
      this.list = this.list.map(item => {
        item.focused = item.id === current.id;
        return item
      })
      const currentItem = this.list.find(item => item.focused);
      const maxZ = this.findTopLayerZ(currentItem);
      if (!maxZ) {
        return;
      }
      currentItem.z = maxZ + 1;
    },
    onContextMenuOpen (e, item) {
      this.$refs.contextMenu.open(e);
      this.onFocus(item);
    },
    drop(e,i){
      let x= e.offsetX - widgetX
      let y= e.offsetY - widgetY
      if(i != undefined){
        x += this.list[i].x;
        y += this.list[i].y
      }
      if(currentWidget.component === 'BoxComp'){
        currentWidget.default.value = this.getRandomString(10)
      }
      this.$refs.contextMenu.close()
      const newItem = {
        id: !this.list.length ? 0 : Math.max(...this.list.map(item => item.id)) +1,
        x: x,
        y: y,
        z: !this.list.length ? 0 : Math.max(...this.list.map(item => item.z)) +1,
        w: currentWidget.default.w,
        h: currentWidget.default.h,
        value: currentWidget.default.value,
        component: currentWidget.component,
        page:currentWidget.page,
        title:currentWidget.default.title,
      }
      this.list.push(newItem);
      this.onFocus(newItem)
      socket.emit('edit_comp', this.list,this.uid,this.page)
    },
    onWidgetMouseDown(e,widget){
      widgetX=e.offsetX
      widgetY=e.offsetY
      currentWidget=widget
    },
  },
}
</script>

<style>
body {
  margin: 0;
  padding: 0;
}
#app{
  display: flex;
  min-height: 100vh;
  min-width: 100vw;
}
.panel{
  flex:1;
  position: relative;
  background-color: #e6eaf0;
  background-image: url("../../src/assets/bg.png");
}
.my-class{
  outline: none;
  position: absolute;
}
.my-dragging-class{
  box-shadow: 7px 7px 8px 0 rgba(0, 0, 0, 0.2);
  position: absolute;
}
.my-active-class {
  border: 2px solid black;
  position: absolute;
}
.drag-cancel:focus {
  outline: none;
}
.share{
  position: absolute;
  bottom:30px;
  right:0;
}
.roomId{
  position: absolute;
  bottom:0;
  right:0;
}
</style>
